// Go服务主程序，提供HTTP接口和数据库操作功能
// 主要包含数据库连接、HTTP请求处理和合规检查功能
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"time"
	"unsafe"

	"github.com/jackc/pgx/v5"
)

/*
#include <stdlib.h>
#include <string.h>

// 声明C库函数
extern void process_data(const char* input, char* output);
extern int contains_phone_number(const char* text);
extern int contains_id_card(const char* text);
extern int contains_email(const char* text);
extern int contains_credit_card(const char* text);
*/
import "C"

// 全局数据库连接对象
var db *pgx.Conn

// ComplianceResult 合规检查结果结构体
// 包含检查结果的完整信息
type ComplianceResult struct {
	ID          int       `json:"id"`
	Data        string    `json:"data"`
	IsCompliant bool      `json:"is_compliant"`
	Issues      []string  `json:"issues"`
	CreatedAt   time.Time `json:"created_at"`
}

// connectDB 连接数据库函数
// 从环境变量获取数据库连接参数，建立数据库连接
// 返回值：连接错误信息
func connectDB() error {
	// 修改为远程数据库连接配置
	dbHost := os.Getenv("DB_HOST")
	if dbHost == "" {
		dbHost = "ecs.sec.hn.cn"  // 远程数据库主机
	}
	
	dbPort := os.Getenv("DB_PORT")
	if dbPort == "" {
		dbPort = "5432"  // 默认PostgreSQL端口
	}
	
	dbUser := os.Getenv("DB_USER")
	if dbUser == "" {
		dbUser = "user_kwmBAP"  // 远程数据库用户名
	}
	
	dbPass := os.Getenv("DB_PASSWORD")
	if dbPass == "" {
		dbPass = "TeHeZKPzzr6mZ6R4"  // 远程数据库密码
	}
	
	dbName := os.Getenv("DB_NAME")
	if dbName == "" {
		dbName = "auditdb"  // 数据库名
	}
	
	dsn := fmt.Sprintf("postgres://%s:%s@%s:%s/%s", dbUser, dbPass, dbHost, dbPort, dbName)
	conn, err := pgx.Connect(context.Background(), dsn)
	if err != nil {
		return err
	}
	db = conn
	return nil
}

// handler 处理根路径HTTP请求的函数
// 接收HTTP请求，将数据写入audit_log表
// 参数：
//   w: HTTP响应写入器
//   r: HTTP请求对象
func handler(w http.ResponseWriter, r *http.Request) {
	input := "Hello Go + DB"
	// 写入数据库示例
	_, err := db.Exec(context.Background(), "INSERT INTO audit_log(data) VALUES($1)", input)
	if err != nil {
		fmt.Fprintf(w, "DB write error: %v", err)
		return
	}
	fmt.Fprintf(w, "Data written to DB: %s", input)
}

// complianceCheckHandler 处理合规检查HTTP请求的函数
// 执行合规检查并将结果存储到数据库，返回JSON格式的检查结果
// 参数：
//   w: HTTP响应写入器
//   r: HTTP请求对象
func complianceCheckHandler(w http.ResponseWriter, r *http.Request) {
	// 获取请求数据
	var requestData struct {
		Text string `json:"text"`
	}
	
	// 解析JSON请求体
	if err := json.NewDecoder(r.Body).Decode(&requestData); err != nil {
		http.Error(w, "Invalid JSON", http.StatusBadRequest)
		return
	}
	
	text := requestData.Text
	
	// 调用C函数检测敏感信息
	cText := C.CString(text)
	defer C.free(unsafe.Pointer(cText))
	
	hasPhone := int(C.contains_phone_number(cText))
	hasIDCard := int(C.contains_id_card(cText))
	hasEmail := int(C.contains_email(cText))
	hasCreditCard := int(C.contains_credit_card(cText))
	
	// 构建合规检查问题列表
	var issues []string
	if hasPhone == 1 {
		issues = append(issues, "包含手机号码")
	}
	if hasIDCard == 1 {
		issues = append(issues, "包含身份证号码")
	}
	if hasEmail == 1 {
		issues = append(issues, "包含邮箱地址")
	}
	if hasCreditCard == 1 {
		issues = append(issues, "包含银行卡号")
	}
	
	// 判断是否合规（简单示例：不包含敏感信息即合规）
	isCompliant := len(issues) == 0
	
	// 构造返回结果
	result := ComplianceResult{
		Data:        text,
		IsCompliant: isCompliant,
		Issues:      issues,
		CreatedAt:   time.Now(),
	}

	// 插入数据库
	issuesJSON, _ := json.Marshal(result.Issues)
	_, err := db.Exec(context.Background(), 
		"INSERT INTO compliance_results(data, is_compliant, issues, created_at) VALUES($1, $2, $3, $4)",
		result.Data, result.IsCompliant, issuesJSON, result.CreatedAt)
	
	if err != nil {
		http.Error(w, fmt.Sprintf("DB write error: %v", err), http.StatusInternalServerError)
		return
	}

	// 返回结果
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(result)
}

// detectHandler 处理敏感信息检测HTTP请求的函数
// 检测文本中的敏感信息并返回脱敏后的结果
// 参数：
//   w: HTTP响应写入器
//   r: HTTP请求对象
func detectHandler(w http.ResponseWriter, r *http.Request) {
	// 获取请求数据
	var requestData struct {
		Text string `json:"text"`
	}
	
	// 解析JSON请求体
	if err := json.NewDecoder(r.Body).Decode(&requestData); err != nil {
		http.Error(w, "Invalid JSON", http.StatusBadRequest)
		return
	}
	
	text := requestData.Text
	
	// 调用C函数检测敏感信息
	cText := C.CString(text)
	defer C.free(unsafe.Pointer(cText))
	
	hasPhone := int(C.contains_phone_number(cText))
	hasIDCard := int(C.contains_id_card(cText))
	hasEmail := int(C.contains_email(cText))
	hasCreditCard := int(C.contains_credit_card(cText))
	
	// 生成脱敏后的输出结果
	// 分配足够大的内存空间
	output := make([]byte, len(text)*2+1)
	cOutput := (*C.char)(unsafe.Pointer(&output[0]))
	C.process_data(cText, cOutput)
	
	// 将C字符串转换为Go字符串
	outputStr := C.GoString(cOutput)
	
	// 构建检测结果列表
	var issues []string
	if hasPhone == 1 {
		issues = append(issues, "包含手机号码")
	}
	if hasIDCard == 1 {
		issues = append(issues, "包含身份证号码")
	}
	if hasEmail == 1 {
		issues = append(issues, "包含邮箱地址")
	}
	if hasCreditCard == 1 {
		issues = append(issues, "包含银行卡号")
	}
	
	// 构造返回结果
	result := struct {
		Input       string   `json:"input"`
		Output      string   `json:"output"`
		Issues      []string `json:"issues"`
		IsSensitive bool     `json:"is_sensitive"`
	}{
		Input:       text,
		Output:      outputStr,
		Issues:      issues,
		IsSensitive: len(issues) > 0,
	}

	// 将原始数据写入审计日志表
	_, err := db.Exec(context.Background(), "INSERT INTO audit_log(data) VALUES($1)", text)
	if err != nil {
		http.Error(w, fmt.Sprintf("DB write error: %v", err), http.StatusInternalServerError)
		return
	}
	
	// 返回结果
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(result)
}

// main 程序入口函数
// 初始化数据库连接，创建数据表，启动HTTP服务
func main() {
	err := connectDB()
	if err != nil {
		panic(err)
	}

	// 初始化表
	db.Exec(context.Background(), `
	CREATE TABLE IF NOT EXISTS audit_log (
		id SERIAL PRIMARY KEY,
		data TEXT,
		created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
	)`)

	db.Exec(context.Background(), `
	CREATE TABLE IF NOT EXISTS compliance_results (
		id SERIAL PRIMARY KEY,
		data TEXT,
		is_compliant BOOLEAN,
		issues JSONB,
		created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
	)`)

	http.HandleFunc("/", handler)
	http.HandleFunc("/compliance", complianceCheckHandler)
	http.HandleFunc("/detect", detectHandler)
	fmt.Println("Go service running at :8080")
	http.ListenAndServe(":8080", nil)
}